package cn.bonoon.services.plugins;

import java.util.Collection;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import cn.bonoon.core.IAccountEditor;
import cn.bonoon.core.plugins.AccountService;
import cn.bonoon.core.plugins.LoginService;
import cn.bonoon.core.plugins.LogonService;
import cn.bonoon.entities.AccountEntity;
import cn.bonoon.entities.AccountPasswordEntity;
import cn.bonoon.entities.RoleAccountEntity;
import cn.bonoon.entities.RoleEntity;
import cn.bonoon.entities.plugins.ShortcutMenuEntity;
import cn.bonoon.kernel.events.OperateEvent;
import cn.bonoon.kernel.exceptions.PasswordVerifierException;
import cn.bonoon.kernel.menus.ChannelDefinition;
import cn.bonoon.kernel.menus.MenuableDefinition;
import cn.bonoon.kernel.menus.ModuleDefinition;
import cn.bonoon.kernel.menus.TabsDefinition;
import cn.bonoon.kernel.menus.privileges.MyPrivilegeInspector;
import cn.bonoon.kernel.menus.privileges.PrivilegeInspector;
import cn.bonoon.kernel.support.IOperator;
import cn.bonoon.kernel.support.PasswordVerifier;
import cn.bonoon.kernel.support.services.AbstractService;
import cn.bonoon.kernel.support.services.PrivilegeSupport;
import cn.bonoon.kernel.util.StringHelper;
import cn.bonoon.policy.PrivilegePolicySourceable;

@Service
@Transactional(readOnly = true)
public class AccountServiceImpl extends AbstractService<AccountEntity> implements AccountService, LoginService, LogonService {
	private final PasswordVerifier passwordVerifier;

	@Autowired
	public AccountServiceImpl(PasswordVerifier passwordVerifier) {
		this.passwordVerifier = passwordVerifier;
	}
	
	@Override
	@Transactional
	public void saveAccount(AccountEntity entity) {
		entityManager.persist(entity);
	}
	
	// ////////////////======================================================
	@Override
	@Transactional
	protected AccountEntity __save(OperateEvent event, AccountEntity entity) throws Exception{
		IAccountEditor pe = (IAccountEditor) event.getSource();
		passwordVerifier.set(entity, pe);
		
		AccountEntity _entity = super.__save(event, entity);
		Long[] roles = pe.getRoles();
		if (null != roles && roles.length > 0) {
			for (Long role : roles) {
				RoleAccountEntity rae = new RoleAccountEntity();
				rae.setAccount(_entity);
				rae.setRole(entityManager.find(RoleEntity.class, role));
				rae.setCreateAt(event.now());
				rae.setCreatorId(event.getId());
				entityManager.persist(rae);
			}
		}
		return _entity;
	}
	
	@Override
	public void verify(IOperator user, String pwd) {
		AccountEntity ae = __get(user.getId());
		Assert.isTrue(passwordVerifier.matches(pwd, ae.getLoginPwd()), "密码验证不通过！");
	}

	@Override
	@Transactional
	public void modify(Long uid, String oldPwd, String newPwd, String repwd) throws PasswordVerifierException {
		AccountEntity ae = __get(uid);
		AccountPasswordEntity ape = new AccountPasswordEntity();
		ape.setOldPassword(ae.getLoginPwd());
		
		passwordVerifier.resetPassword(ae, oldPwd, newPwd, repwd);
		
		ae.setForcedChangePwd(false);
		Date now = new Date();
		ae.setPasswordUpdateAt(now);
		entityManager.merge(ae);
		
		ape.setNewPassword(ae.getLoginPwd());
		ape.setAccount(ae);
		ape.setCreateAt(now);
		ape.setCreatorId(ae.getId());
		ape.setCreatorName(ae.getLoginName());
		ape.setSelf(true);
		entityManager.persist(ape);
	}

	@Override
	@Transactional
	public String resetPassword(IOperator opt, Long id, String pwd, String repwd, boolean enforce) throws PasswordVerifierException {
		AccountEntity ae = get(id);
		AccountPasswordEntity ape = new AccountPasswordEntity();
		ape.setOldPassword(ae.getLoginPwd());
		passwordVerifier.setPassword(ae, pwd, repwd);
		
		ae.setForcedChangePwd(enforce);
		Date now = new Date();
		ae.setPasswordUpdateAt(now);
		entityManager.merge(ae);

		ape.setNewPassword(ae.getLoginPwd());
		ape.setAccount(ae);
		ape.setCreateAt(now);
		ape.setCreatorId(opt.getId());
		ape.setCreatorName(opt.getUsername());
		entityManager.persist(ape);
		
		return pwd;
	}
	
	@Override
	@Transactional
	public String randomPassword(IOperator opt, Long id, boolean enforce) throws PasswordVerifierException {
		AccountEntity ae = get(id);
		AccountPasswordEntity ape = new AccountPasswordEntity();
		ape.setOldPassword(ae.getLoginPwd());
		String pwd = passwordVerifier.randomPassword(ae);
		ae.setForcedChangePwd(enforce);
		Date now = new Date();
		ae.setPasswordUpdateAt(now);
		entityManager.merge(ae);

		ape.setNewPassword(ae.getLoginPwd());
		ape.setAccount(ae);
		ape.setCreateAt(now);
		ape.setCreatorId(opt.getId());
		ape.setCreatorName(opt.getUsername());
		entityManager.persist(ape);
		
		return pwd;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<ShortcutMenuEntity> shortcutMenus(IOperator opt, String moduleId) {
		Long uid = opt.getId();
		
//		String rids;
//		String ql_role = "select distinct x.role.id from RoleAccountEntity x where x.account.id=?";
//		List<Long> rold_ids = __list(Long.class, ql_role, uid);
//		int size = rold_ids.size();
//		if (size == 1) {
//			rids = "x.role.id=" + rold_ids.get(0);
//		} else if (size > 1) {
//			StringBuilder sb = new StringBuilder();
//			for (Long rid : rold_ids) {
//				sb.append(',').append(rid);
//			}
//			rids = "x.role.id in(" + sb.substring(1) + ")";
//		} else {
//			rids = "x.role.id=-1";
//		}
//
//		String ql_privilege = "select distinct x.meunId from BasePrivilegeEntity x where x.account.id=? or " + rids;
//		List<String> privilege_ids = __list(String.class, ql_privilege, uid);
//
//		String ql_menu = "from ShortcutMenuEntity x where x.owner=? and x.moduleId=? order by x.ordinal asc, x.createAt asc";
//		List<ShortcutMenuEntity> menus = __list(ShortcutMenuEntity.class, ql_menu, uid, moduleId);
//		
//		Iterator<ShortcutMenuEntity> iter = menus.iterator();
//		while (iter.hasNext()) {
//			ShortcutMenuEntity menu = iter.next();
//			if (!privilege_ids.contains(menu.getMenuId())) {
//				iter.remove();
//			}
//		}
//		return menus;
		//如果是超级管理员，则不需要连表判断
		if(opt.isSuper()){
			String ql = "select x from ShortcutMenuEntity x where x.owner=? and x.moduleId=? order by x.ordinal asc";
			return entityManager.createQuery(ql, ShortcutMenuEntity.class).setParameter(1, uid).setParameter(2, moduleId).getResultList();
		}
		String sql = "select x.* from T_SHORTCUTMENU x inner join T_PRIVILEGE y on x.C_MENUID=y.C_MENUID";
		sql += " inner join T_ROLEASSIGN z on (y.R_ROLE_ID=z.R_ROLE_ID or y.R_ACCOUNT_ID=z.R_ACCOUNT_ID) and x.C_OWNER=z.R_ACCOUNT_ID";
		sql += " where x.C_OWNER=? and x.C_MODULEID=? order by x.C_ORDINAL asc, x.C_CREATEAT asc";
		return entityManager.createNativeQuery(sql, ShortcutMenuEntity.class).setParameter(1, uid).setParameter(2, moduleId).getResultList();
	}

//	@Autowired(required = false)
//	private OnLoginUserLoad loginUserLoad;
	
	private final String _0 = "select x from AccountEntity x where x.deleted=false and x.loginName=?";
	@Override
	public AccountEntity loadByLoginName(String loginName) {
		if(StringHelper.isEmpty(loginName)) return null;
		AccountEntity user = __first(domainClass, _0, loginName);
//		if(null != loginUserLoad){
//			return loginUserLoad.load(user);
//		}
		return user;
	}

	private final String _1 = "select distinct x.role.moduleKey from RoleAccountEntity x where x.account.id=? and x.invalid=false and x.role.deleted=false and x.role.status=1";
	@Override
	public Collection<String> accessableModules(IOperator user) {
		return __list(String.class, _1, user.getId());
	}

	private PrivilegeInspector __privilege(IOperator user, String mid, String cid, String pid) {
		if (user.isSuper()) {
			return PrivilegeInspector.ALL;
		}

		Long uid = user.getId();
		String roleql = __role(mid, uid);
		String cql = "select distinct x.channelId from PrivilegeEntity x where x.moduleId=? and x.account.id=?" + roleql;
		String mql = "select distinct x.meunId from PrivilegeEntity x where x.moduleId=? and x.account.id=?" + roleql;

		return new MyPrivilegeInspector(mid, cid, pid, __list(String.class, cql, mid, uid), __list(String.class, mql, mid, uid));
	}

	private final String _2 = "select distinct x.role.id from RoleAccountEntity x where x.role.moduleKey=? and x.account.id=? and x.invalid=false and x.role.deleted=false and x.role.status=1";
	private String __role(String mid, Long uid) {
		List<Long> rids = __list(Long.class, _2, mid, uid);
		int size = rids.size();
		if (size == 1) {
			return " or x.role.id=" + rids.get(0);
		}
		if (size > 1) {
			StringBuilder sb = new StringBuilder();
			for (Long rid : rids) {
				sb.append(',').append(rid);
			}
			return " or x.role.id in(" + sb.substring(1) + ")";
		}
		return "";
	}

	private final String _3 = "select distinct x.role.roleKey from RoleAccountEntity x where x.account.id=? and x.invalid=false and x.role.deleted=false and x.role.status=1";
	
	@Override
	public List<String> getAccountRoles(Long uid) {
		return __list(String.class, _3, uid);
	}
	
	@Override
	public List<RoleEntity> getAccountRoles(AccountEntity user) {
		String ql = "select distinct x.role from RoleAccountEntity x where x.account.id=? and x.invalid=false and x.role.deleted=false and x.role.status=1";
		return __list(RoleEntity.class, ql, user.getId());
	}

	private final String _4 = "select distinct x.meunId from AccountPrivilegeEntity x where x.moduleId=? and x.channelId=? and x.account.id=? and x.invalid=false";
	
	@Override
	public List<String> getMenuIds(Long userId, ChannelDefinition item) {
		return __list(String.class, _4, item.getModule().getId(), item.getId(), userId);
	}

	
	// ------------------------------------20171230支持统一权限管理
	
	@Override
	public void afterPropertiesSet() throws Exception {
		super.afterPropertiesSet();
		
		//判断是否定义了把用户的操作权限缓存起来
		if(null == privilegeSupport){
			//使用即时的访问策略
			privilegeSupport = new InternalPrivilegeSupport();
		}else if(privilegeSupport instanceof PrivilegePolicySourceable){
			((PrivilegePolicySourceable) privilegeSupport).set(new InternalPrivilegeSupport());
		}
	}
	
	@Autowired(required = false)
	private PrivilegeSupport privilegeSupport;
	
	@Override
	public PrivilegeSupport policy() {
		return privilegeSupport;
	}
	
	private class InternalPrivilegeSupport implements PrivilegeSupport{
	
		@Override
		public List<Long> getActions(MenuableDefinition item, IOperator user) {
			Long uid = user.getId();
			String roleql = __role(item.getModule().getId(), uid);
			String ql = "select x.actions from RolePrivilegeEntity x where x.meunId=? and x.invalid=false and " + roleql;
			return __list(Long.class, ql, item.getId());
		}
	
		@Override
		public PrivilegeInspector privilege(IOperator user, String mid, String cid) {
			return __privilege(user, mid, cid, cid);
		}
		
		@Override
		public PrivilegeInspector privilege(IOperator user, MenuableDefinition item) {
			String pid = item.getId(); // F0E2761FA4FACB39260838964D2910E1
			String cid = item.getChannel().getId(); // 9BAE24200416CF92AF47B1BC137E9E41
			String mid = item.getModule().getId(); // 66CD9CB1900481637F0C9DECC65A05F0
			return __privilege(user, mid, cid, pid);
		}
	
		@Override
		public PrivilegeInspector privilege(IOperator user, TabsDefinition tab) {
			String pid = tab.getId();
			String cid = tab.getChannel().getId();
			String mid = tab.getModule().getId();
			return __privilege(user, mid, cid, pid);
		}
	
		@Override
		public PrivilegeInspector privilege(IOperator user, ModuleDefinition module) {
			return __privilege(user, module.getId(), null, null);
		}

		@Override
		public ModuleDefinition policy(Object user, Class<?> acceptClass, Object privilege) {
			/*
			 * 默认的方式是使用动态处理，即用户每次进入菜单的时候，系统都会重新加载该用户的访问权限
			 */
			return null;
		}
	
	}
}
